import httpx
import json
from typing import Any, List, Dict
from mcp.server.fastmcp import FastMCP
from pydantic import BaseModel

# Initialize FastMCP server
mcp = FastMCP("mapServer")

# API配置
API_URL = "https://api.map.baidu.com"
USER_AGENT = "map-app/1.0"
API_KEY = ""

class TravelOption(BaseModel):
    duration: str  # 预计行驶时间
    distance: str  # 行驶距离
    traffic_condition: List[List[Dict[str, Any]]]
    toll: str  # 收费金额
    detail: List[str]  # 详细导航步骤

async def geocode(address: str) -> dict:
    """
    将文字地址转换为经纬度
    :param address: 地址名称，如 "北京西站"
    :return: { "status": 0, "lat": 39.936404, "lng": 116.339303 } 或错误信息
    """
    url = "https://api.map.baidu.com/geocoding/v3/" #刚测试了两下就给我发信息，提示并发量已达上限。地理编码的使用次数上限是0.5万次/天

    params = {
        "address": address,
        "output": "json",
        "ak": API_KEY
    }

    async with httpx.AsyncClient() as client:
        try:
            response = await client.get(url, params=params, timeout=10.0)
            data = response.json()

            if data.get("status") == 0:
                loc = data["result"]["location"]
                return {
                    "status": 0,
                    "lng": loc["lng"],
                    "lat": loc["lat"]
                }
            else:
                return {"status": -1, "message": data.get("message", "地理编码失败")}
        except Exception as e:
            return {"status": -1, "message": f"请求地理编码失败: {str(e)}"}

async def get_navigation(origin: str, destination: str) -> Dict[str, Any]:
    """调用百度地图API获取驾车导航信息"""
    # 交通方式: https://lbsyun.baidu.com/faq/api?title=webapi/webservice-direction/dirve
    endpoint = f"{API_URL}/direction/v2/driving"
    params = {
        "origin": origin,  # 起点经纬度，小数点后不超过6位，40.056878,116.30815
        "destination": destination,  # 终点经纬度，小数点后不超过6位，40.056878,116.30815
        "tactics": 0,  # 导航策略：默认
        "coord_type": "bd09ll",
        "ak": API_KEY,
    }

    headers = {"User-Agent": USER_AGENT}

    async with httpx.AsyncClient() as client:
        try:
            response = await client.get(endpoint, params=params, headers=headers, timeout=10.0)
            response.raise_for_status()
            return response.json()
        except httpx.HTTPStatusError as e:
            return {"error": f"HTTP错误: {e.response.status_code}"}
        except Exception as e:
            return {"error": f"Request failed: {str(e)}"}


def format_navigation(data: Dict[str, Any]) -> str:
    """格式化导航结果"""
    if "error" in data:
        return f"导航查询失败: {data['error']}"

    if data.get("status") != 0:
        return f"百度地图API错误: {data.get('message', '未知错误')}"

    if not data.get("result", {}).get("routes"):
        return "未找到合适的驾驶路线"

    # 处理第一条路线（通常是最佳路线）
    route = data["result"]["routes"][0]

    # 计算行驶时间（小时+分钟）
    duration_seconds = route["duration"]
    hours = duration_seconds // 3600
    minutes = (duration_seconds % 3600) // 60
    duration_str = f"{hours}小时{minutes}分钟" if hours > 0 else f"{minutes}分钟"

    # 格式化距离
    distance_km = route["distance"] / 1000
    distance_str = f"{distance_km:.1f}公里"

    # 通行费
    toll_str = f"{route['toll']}元" if route.get('toll', 0) > 0 else "免费"

    # 提取详细步骤
    steps = []
    traffic_conditions = []

    for step in route["steps"]:
        # 构造路段描述
        road_name = step.get("road_name", "未知道路")
        if road_name == "无名路":
            road_name = "某路段"
        distance_step = step["distance"] / 1000  # 米 → 公里
        instruction = f"沿{road_name}行驶{distance_step:.1f}公里"

        steps.append(instruction)

        # 提取 traffic_condition
        tc_list = step.get("traffic_condition", [])
        traffic_conditions.append(tc_list)

    # 创建 TravelOption（确保模型字段匹配）
    option = TravelOption(
        duration=duration_str,
        distance=distance_str,
        toll=toll_str,
        detail=steps,
        traffic_condition=traffic_conditions
    )

    # 格式化输出
    formatted = "🚗 驾车导航方案：\n"
    formatted += f"  ⏱ 时长: {option.duration}\n"
    formatted += f"  📏 距离: {option.distance}\n"
    formatted += f"  💰 通行费: {option.toll}\n\n"

    formatted += "  🛣️ 路线详情（含路况）：\n"
    for i, (desc, tcs) in enumerate(zip(option.detail, option.traffic_condition), 1):
        formatted += f"  {i}. {desc}\n"

        if tcs:
            tc_parts = []
            for tc in tcs:
                status = tc.get("status", 0)
                tc_distance = tc.get("distance", 0) / 1000  # 米 → 公里
                status_text = {0: "无路况", 1: "畅通", 2: "缓行", 3: "拥堵", 4: "严重拥堵"}.get(status, "未知")
                emoji = "🟢" if status == 1 else "🟡" if status == 2 else "🟠" if status == 3 else "🔴" if status == 4 else "⚪"
                tc_parts.append(f"{emoji}{tc_distance:.1f}km({status_text})")
            formatted += "     🚦 路况: " + " ".join(tc_parts) + "\n"
        else:
            formatted += "     🚦 路况: 未知\n"

    return formatted

@mcp.tool()
async def query_navigation(origin: str, destination: str) -> str:
    """
    城市导航查询工具
    :param origin: 起点（如：清华大学东门）
    :param destination: 终点城市名称（如"北京工人体育场"）
    :return: 格式化后的导航信息
    """
    # Step 1: 地址转坐标
    start = await geocode(origin)
    end = await geocode(destination)

    if start.get("status") != 0:
        return f"❌ 无法解析起点: {start.get('message', '未知错误')}"

    if end.get("status") != 0:
        return f"❌ 无法解析终点: {end.get('message', '未知错误')}"

    # Step 2: 格式化为 "经度,纬度"
    origin_coord = f"{start['lat']}, {start['lng']}"
    dest_coord = f"{end['lat']}, {end['lng']}"

    # Step 3: 调用导航 API
    data = await get_navigation(origin_coord, dest_coord)
    return format_navigation(data)

if __name__ == '__main__':
    mcp.run(transport='stdio')

    # # 运行测试
    # import asyncio
    # async def main():
    #     print("测试地理编码...")
    #     result = await geocode("清华大学东门")
    #     print(result)
    #
    #     print("🔍 正在测试导航功能...")
    #     # result = await query_navigation("清华大学东门", "北京工人体育场")
    #     result = await query_navigation("清华大学东门", "天津大学(卫津路校区)")
    #     print("\n" + "=" * 50)
    #     print("测试结果：")
    #     print(result)
    #     print("=" * 50)
    #
    # asyncio.run(main())